<?php
namespace app\socket\controller;

use my\Security;
use think\worker\Server;
use Workerman\Lib\Timer;

class SocketAdmin extends Server
{
    const HEARTBEAT_TIME = 25;
    protected $socket = ADMIN;
    protected $name = 'admin';
    protected $processes = 1;
    // 全局数组保存uid在线数据
    protected $uidConnectionMap = array();
    protected $idUidMap = array();
    // 记录最后一次广播的在线用户数
    protected $last_online_count = 0;
    // 记录最后一次广播的在线页面数
    protected $last_online_page_count = 0;

    /**
     * 收到信息
     *
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
    {
//        echo $connection->lastMessageTime.'---'.$connection->id.':'.$data."\r\n";
        $connection->lastMessageTime = time();
    }

    /**
     * 当连接建立时触发的回调函数
     *
     * @param $connection
     */
    public function onConnect($connection)
    {
        $connection->onWebSocketConnect = function($connection , $http_header)
        {
            $encode = $_GET['encode'];
            $all_arr = Security::decrypt($encode);
            var_dump($all_arr);
            if(empty($all_arr)){
                $connection->close();
            }
            $data = json_decode($all_arr,true);
            if(empty($data)){
                $connection->close();
            }
            // 更新对应uid的在线数据
            $admin_id = (int)$data['admin_id'];
            // 已经登录过了
            if(isset($this->uidConnectionMap[$admin_id])){
                return;
            }
            $this->uidConnectionMap[$admin_id] = $connection;
            $connection->uid = $admin_id;
            $msg['type'] = 'login';
            $msg['content'] = $data['admin_name']."已上线";
            $this->sendMessage(json_encode($msg),array($admin_id),false);
        };
    }

    /**
     * 当连接断开时触发的回调函数
     *
     * @param $connection
     */
    public function onClose($connection)
    {
        /**
         * 这里如果设备异常断开，
         * 会导致同一台设备再此连接时候也以序列号
         * 为uid标识的设备也被unset掉
         */
         if (isset($connection->uid)) {
             // 连接断开时删除映射
             unset($this->uidConnectionMap[$connection->uid]);
         }
//         $s2= "\r\n连接id：" . $connection->id;
//         echo iconv('UTF-8','GBK',$s2) . "  disconnect \r\n";
    }

    /**
     * 当客户端的连接上发生错误时触发
     *
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     *
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        // 开启一个内部端口，方便内部系统推送数据
        /*$inner_text_worker = new Worker(INNER_HTTP);
        $inner_text_worker->onMessage = function($http_connection, $buffer)
        {
            $_POST = $_POST ? $_POST : $_GET;
            // 推送数据的url格式 type=publish&to=uid&content=xxxx
            switch(@$_POST['type']){
                case 'publish':
                    $to = @$_POST['to'];
                    $_POST['content'] = htmlspecialchars(@$_POST['content']);
                    // 有指定uid则向uid所在socket组发送数据
                    if($to){
                        if(!isset($this->uidConnectionMap[$to])){
                            return $http_connection->send(json_encode(array('status'=>0,'msg'=>'offline')));
                        }
                        $this->sendMessageByUid($to,json_encode($_POST));
                        // 否则向所有uid推送数据
                    }else{
                        if(empty($this->uidConnectionMap)){
                            $http_connection->send(json_encode(array('status'=>0,'msg'=>'none online')));
                        }
                        $this->sendMessage(json_encode($_POST));
                    }
                    // http接口返回，如果用户离线socket返回fail
                    return $http_connection->send(json_encode(array('status'=>1,'msg'=>'ok')));
                    break;
                default:break;
            }
        };
        $inner_text_worker->listen();*/
        // 进程启动后设置一个每秒运行一次的定时器
        Timer::add(1, function ()use($worker){
            $time_now = time();
            foreach ($worker->connections as $connection) {
                // 有可能该connection还没收到过消息，则lastMessageTime设置为当前时间
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }
                // 上次通讯时间间隔大于心跳间隔，则认为客户端已经下线，关闭连接
                if ($time_now - $connection->lastMessageTime > self::HEARTBEAT_TIME) {
                    if (isset($connection->uid)) {
                        // 连接断开时删除映射
                        unset($this->uidConnectionMap[$connection->uid]);
                    }
                    $connection->close();
                }
            }
        });
    }

    // 针对uid推送数据
    private function sendMessageByUid($uid, $message)
    {
        if(isset($this->uidConnectionMap[$uid]))
        {
            $connection = $this->uidConnectionMap[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }

    /**
     * 群发信息
     * @param $message //消息
     * @param $send_to //指定人ID数组
     * @param $flag //true 发给指定人，false不发给指定人
     * @return  boolean
     * */
    private function sendMessage($message,$send_to = array(),$flag = true)
    {
        if(!empty($this->uidConnectionMap)){
            var_dump($message);
            foreach ($this->uidConnectionMap as $key => $connection){
                if($flag){
                    if(empty($send_to)){
                        $connection->send($message);
                    }else{
                        if(in_array($key,$send_to)){
                            $connection->send($message);
                        }
                    }
                }else{
                    if(!in_array($key,$send_to)){
                        $connection->send($message);
                    }
                }
            }
            return true;
        }
        return false;
    }
}